+++ LICENSE-slock
@@ -0,0 +1,24 @@
+MIT/X Consortium License
+
+© 2015-2016 Markus Teich <markus.teich@stusta.mhn.de>
+© 2014 Dimitris Papastamos <sin@2f30.org>
+© 2006-2014 Anselm R Garbe <anselm@garbe.us>
+© 2014-2016 Laslo Hunhold <dev@frign.de>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+++ Makefile
@@ -17,13 +17,12 @@
 CPPFLAGS += -D_GNU_SOURCE
 CFLAGS += $(shell $(PKG_CONFIG) --cflags cairo xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11)
 LIBS += $(shell $(PKG_CONFIG) --libs cairo xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11)
-LIBS += -lpam
 LIBS += -lev
 LIBS += -lm
 
-# OpenBSD lacks PAM, use bsd_auth(3) instead.
+# On OpenBSD we use bsd_auth(3) instead.
 ifneq ($(UNAME),OpenBSD)
-  LIBS += -lpam
+  LIBS += -lcrypt
 endif
 
 FILES:=$(wildcard *.c)
@@ -51,9 +50,7 @@
 
 install: all
 	$(INSTALL) -d $(DESTDIR)$(PREFIX)/bin
-	$(INSTALL) -d $(DESTDIR)$(SYSCONFDIR)/pam.d
 	$(INSTALL) -m 755 i3lock $(DESTDIR)$(PREFIX)/bin/i3lock
-	$(INSTALL) -m 644 i3lock.pam $(DESTDIR)$(SYSCONFDIR)/pam.d/i3lock
 
 uninstall:
 	rm -f $(DESTDIR)$(PREFIX)/bin/i3lock
@@ -62,7 +59,7 @@
 	[ ! -d i3lock-${VERSION} ] || rm -rf i3lock-${VERSION}
 	[ ! -e i3lock-${VERSION}.tar.bz2 ] || rm i3lock-${VERSION}.tar.bz2
 	mkdir i3lock-${VERSION}
-	cp *.c *.h i3lock.1 i3lock.pam Makefile LICENSE README.md CHANGELOG i3lock-${VERSION}
+	cp *.c *.h i3lock.1 Makefile LICENSE README.md CHANGELOG i3lock-${VERSION}
 	sed -e 's/^\s*I3LOCK_VERSION:=\(.*\)/I3LOCK_VERSION:=$(shell /bin/echo '${I3LOCK_VERSION}' | sed 's/\\/\\\\/g')/g;s/^VERSION:=\(.*\)/VERSION:=${VERSION}/g' Makefile > i3lock-${VERSION}/Makefile
 	tar cfj i3lock-${VERSION}.tar.bz2 i3lock-${VERSION}
 	rm -rf i3lock-${VERSION}
+++ i3lock.1
@@ -43,8 +43,6 @@
 You can specify either a background color or a PNG image which will be displayed while your screen is locked.
 .IP \[bu]
 You can specify whether i3lock should bell upon a wrong password.
-.IP \[bu]
-i3lock uses PAM and therefore is compatible with LDAP, etc.
 
 
 .SH OPTIONS
@@ -66,8 +64,7 @@
 .B \-u, \-\-no-unlock-indicator
 Disable the unlock indicator. i3lock will by default show an unlock indicator
 after pressing keys. This will give feedback for every keypress and it will
-show you the current PAM state (whether your password is currently being
-verified or whether it is wrong).
+show you whether your password is currently being verified or whether it is wrong.
 
 .TP
 .BI \-i\  path \fR,\ \fB\-\-image= path
@@ -95,7 +92,7 @@
 .TP
 .B \-e, \-\-ignore-empty-password
 When an empty password is provided by the user, do not validate
-it. Without this option, the empty password will be provided to PAM
+it. Without this option, the empty password will be validated
 and, if invalid, the user will have to wait a few seconds before
 another try. This can be useful if the XF86ScreenSaver key is used to
 put a laptop to sleep and bounce on resume or if you happen to wake up
+++ i3lock.c
@@ -21,7 +21,9 @@
 #ifdef __OpenBSD__
 #include <bsd_auth.h>
 #else
-#include <security/pam_appl.h>
+#include <shadow.h>
+#include <grp.h>
+#include <errno.h>
 #endif
 #include <getopt.h>
 #include <string.h>
@@ -57,7 +59,7 @@
 xcb_window_t win;
 static xcb_cursor_t cursor;
 #ifndef __OpenBSD__
-static pam_handle_t *pam_handle;
+const char *hash = NULL;
 #endif
 int input_position = 0;
 /* Holds the password you enter (in UTF-8). */
@@ -90,6 +92,37 @@
 bool ignore_empty_password = false;
 bool skip_repeated_empty_password = false;
 
+/*
+ * Shamelessly stolen from slock. See LICENSE-slock.
+ * This adjusts the process' out of memory score,
+ *  so it isn't killed by the kernel under any circumstances.
+ */
+#ifdef __linux__
+#include <fcntl.h>
+#include <linux/oom.h>
+
+static void
+dontkillme(void)
+{
+	FILE *f;
+	const char oomfile[] = "/proc/self/oom_score_adj";
+
+	if (!(f = fopen(oomfile, "w"))) {
+		if (errno == ENOENT)
+			return;
+		errx(EXIT_FAILURE, "fopen %s: %s", oomfile, strerror(errno));
+	}
+	fprintf(f, "%d", OOM_SCORE_ADJ_MIN);
+	if (fclose(f)) {
+		if (errno == EACCES)
+			errx(EXIT_FAILURE, "unable to disable OOM killer. "
+			                   "Make sure to suid or sgid i3lock.");
+		else
+			errx(EXIT_FAILURE, "fclose %s: %s", oomfile, strerror(errno));
+	}
+}
+#endif
+
 /* isutf, u8_dec © 2005 Jeff Bezanson, public domain */
 #define isutf(c) (((c)&0xC0) != 0x80)
 
@@ -281,16 +314,16 @@
         exit(0);
     }
 #else
-    if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
-        DEBUG("successfully authenticated\n");
-        clear_password_memory();
+    /*
+     * Shamelessly stolen from slock. See LICENSE-slock.
+     */
+    char *inputhash;
 
-        /* PAM credentials should be refreshed, this will for example update any kerberos tickets.
-         * Related to credentials pam_end() needs to be called to cleanup any temporary
-         * credentials like kerberos /tmp/krb5cc_pam_* files which may of been left behind if the
-         * refresh of the credentials failed. */
-        pam_setcred(pam_handle, PAM_REFRESH_CRED);
-        pam_end(pam_handle, PAM_SUCCESS);
+    if (!(inputhash = crypt(password, hash)))
+        fprintf(stderr, "crypt: %s", strerror(errno));
+    else if (!strcmp(inputhash, hash)) {
+        DEBUG("successfully authenticated");
+        clear_password_memory();
 
         exit(0);
     }
@@ -626,39 +659,6 @@
     redraw_screen();
 }
 
-#ifndef __OpenBSD__
-/*
- * Callback function for PAM. We only react on password request callbacks.
- *
- */
-static int conv_callback(int num_msg, const struct pam_message **msg,
-                         struct pam_response **resp, void *appdata_ptr) {
-    if (num_msg == 0)
-        return 1;
-
-    /* PAM expects an array of responses, one for each message */
-    if ((*resp = calloc(num_msg, sizeof(struct pam_response))) == NULL) {
-        perror("calloc");
-        return 1;
-    }
-
-    for (int c = 0; c < num_msg; c++) {
-        if (msg[c]->msg_style != PAM_PROMPT_ECHO_OFF &&
-            msg[c]->msg_style != PAM_PROMPT_ECHO_ON)
-            continue;
-
-        /* return code is currently not used but should be set to zero */
-        resp[c]->resp_retcode = 0;
-        if ((resp[c]->resp = strdup(password)) == NULL) {
-            perror("strdup");
-            return 1;
-        }
-    }
-
-    return 0;
-}
-#endif
-
 /*
  * This callback is only a dummy, see xcb_prepare_cb and xcb_check_cb.
  * See also man libev(3): "ev_prepare" and "ev_check" - customise your event loop
@@ -813,10 +813,6 @@
     struct passwd *pw;
     char *username;
     char *image_path = NULL;
-#ifndef __OpenBSD__
-    int ret;
-    struct pam_conv conv = {conv_callback, NULL};
-#endif
     int curs_choice = CURS_NONE;
     int o;
     int optind = 0;
@@ -842,6 +838,48 @@
     if ((username = pw->pw_name) == NULL)
         errx(EXIT_FAILURE, "pw->pw_name is NULL.\n");
 
+#ifndef __OpenBSD__
+    /*
+     * Shamelessly stolen from slock. See LICENSE-slock.
+     *
+     * Slock has code to make it run as nobody:nogroup, which has the added
+     *  security that the locker can only be killed by root.
+     * It causes problems with the xcb_connect in raise_loop, however,
+     *  and I'm not aware of any other methods to keep the calling user from
+     *  killing the locker.
+     * This means that a malicious program running as your user
+     *  could easily bypass your locker by killing it.
+     * However, if such a program even manages to be running, you're pretty
+     *  screwed regardless.
+     */
+
+#ifdef __linux__
+    dontkillme();
+#endif
+
+    hash = pw->pw_passwd;
+
+    if (!strcmp(hash, "x")) {
+        struct spwd *sp;
+        if (!(sp = getspnam(pw->pw_name)))
+            errx(EXIT_FAILURE, "getspnam: cannot retrieve shadow entry. "
+                               "Make sure to suid or sgid i3lock.");
+        hash = sp->sp_pwdp;
+    }
+
+    errno = 0;
+    if (!crypt("", hash))
+        errx(EXIT_FAILURE, "crypt: %s", strerror(errno));
+
+    /* drop privileges */
+    if (setgroups(0, NULL) < 0)
+        errx(EXIT_FAILURE, "setgroups: %s", strerror(errno));
+    if (setgid(pw->pw_gid) < 0)
+        errx(EXIT_FAILURE, "setgid: %s", strerror(errno));
+    if (setuid(pw->pw_uid) < 0)
+        errx(EXIT_FAILURE, "setuid: %s", strerror(errno));
+#endif
+
     char *optstring = "hvnbdc:p:ui:teI:f";
     while ((o = getopt_long(argc, argv, optstring, longopts, &optind)) != -1) {
         switch (o) {
@@ -910,15 +948,6 @@
      * the unlock indicator upon keypresses. */
     srand(time(NULL));
 
-#ifndef __OpenBSD__
-    /* Initialize PAM */
-    if ((ret = pam_start("i3lock", username, &conv, &pam_handle)) != PAM_SUCCESS)
-        errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
-
-    if ((ret = pam_set_item(pam_handle, PAM_TTY, getenv("DISPLAY"))) != PAM_SUCCESS)
-        errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
-#endif
-
 /* Using mlock() as non-super-user seems only possible in Linux.
  * Users of other operating systems should use encrypted swap/no swap
  * (or remove the ifdef and run i3lock as super-user).
+++ i3lock.pam
@@ -1,6 +0,0 @@
-#
-# PAM configuration file for the i3lock screen locker. By default, it includes
-# the 'login' configuration file (see /etc/pam.d/login)
-#
-
-auth include login
